// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.ui.web.browser;

import java.util.ArrayList;
import java.util.List;

import org.dengues.ui.web.browser.dom.DocumentContext;
import org.dengues.ui.web.browser.dom.HTMLDocument;
import org.dengues.ui.web.browser.dom.Node;
import org.dengues.ui.web.browser.event.DenguesProgressEvent;
import org.dengues.ui.web.browser.event.DenguesProgressListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.ole.win32.Variant;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

/**
 * A <code>ZabidooBrowser</code> class is a typical use of <code>ZSwtBrowser</code> class. The property document is
 * used to get the HTML Document element.
 * 
 * @author jliu
 */
public class DenguesBrowser {

    private final DenguesSWTBrowser browser;

    private HTMLDocument document;

    private LocationBinder locationBinder;

    private DocumentContext documentContext;

    private final List<DenguesProgressListener> userListeners;

    /**
     * Create a new browser and add ProgressListener.
     * 
     * @param parent
     */
    public DenguesBrowser(Composite parent) {
        userListeners = new ArrayList<DenguesProgressListener>();

        browser = new DenguesSWTBrowser(parent, SWT.NONE);
        browser.setLayoutData(new GridData(GridData.FILL_BOTH));
        browser.addProgressListener(new DenguesProgressListener() {

            public void changed(DenguesProgressEvent event) {
                performChanged(event);
            }

            public void completed(DenguesProgressEvent event) {
                performCompleted(event);
            }
        });
    }

    /**
     * Initialize the document element when the web page is loaded. We need to calculate and save the bounds of each
     * element, too.
     * 
     * @return True if initialize successfully.
     */
    private boolean initDocument() {
        Variant docVariant = browser.getDocument();
        if (docVariant != null) {
            document = getDocumentContext().getDocument(docVariant.getDispatch());
            locationBinder = new LocationBinder(document);
            Display.getDefault().syncExec(new Runnable() {

                public void run() {
                    locationBinder.saveLocations();
                }
            });// : check necessary for this.
            return true;
        }
        return false;
    }

    /**
     * Perform user ProgressListener.
     * 
     * @param event
     */
    private void performChanged(DenguesProgressEvent event) {
        for (DenguesProgressListener listener : userListeners) {
            listener.changed(event);
        }
    }

    /**
     * Perform Progress Completed event.
     * 
     * @param event
     */
    private synchronized void performCompleted(DenguesProgressEvent event) {
        boolean initialized = initDocument();
        if (!initialized) {
            return;
        }
        for (DenguesProgressListener listener : userListeners) {
            listener.completed(event);
        }
    }

    /**
     * Navigate a new URL, if browser is busy, we should stop then start a new one. The DocumentContext must be reset to
     * a new document.
     * 
     * @param url
     */
    public void navigate(String url) {
        if (browser.isBusy()) {
            browser.stop();
        }
        getDocumentContext().reset();
        browser.navigate(url);
    }

    /**
     * Get HTML Document element.
     * 
     * @return
     */
    public HTMLDocument getDocument() {
        if (document == null) {
            initDocument();
        }
        return document;
    }

    /**
     * Get document context property.
     * 
     * @return
     */
    private DocumentContext getDocumentContext() {
        if (documentContext == null) {
            documentContext = new DocumentContext();
        }
        return documentContext;
    }

    /**
     * Get a node by using current anchor, this will used <code>LocationBinder</code> property.
     * 
     * @param anchor
     * @return a node at current anchor.
     */
    public Node getNodeAt(Point anchor) {
        return locationBinder.getElementAt(anchor);
    }

    /**
     * Get a node by using current anchor, this will used <code>LocationBinder</code> property.
     * 
     * @param x
     * @param y
     * @return a node at current x and y anchor.
     */
    public Node getNodeAt(int x, int y) {
        return getNodeAt(new Point(x, y));
    }

    /**
     * Create a image for current web page from this browser.
     */
    public Image createImage() {
        return ImageCapture.getImage(browser.getOleFrame());
    }

    /**
     * Add a <code>ZProgressListener</code> .
     * 
     * @param listener
     */
    public void addProgressListener(DenguesProgressListener listener) {
        userListeners.add(listener);
    }

    /**
     * Remove a <code>ZProgressListener</code> .
     * 
     * @param listener
     */
    public void removeProgressListener(DenguesProgressListener listener) {
        userListeners.remove(listener);
    }

    /**
     * Refresh.
     */
    public void refresh() {
        browser.refresh();
    }

    public void stop() {
        browser.stop();
    }

    /**
     * Dispose.
     */
    public void dispose() {
        // if (!browser.isBusy()){
        browser.dispose();
        if (locationBinder != null) {
            locationBinder.clear();
            locationBinder = null;
        }
        // userListeners.clear();
        // }
    }
}
